home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-11-26 | 40.3 KB | 1,876 lines |
- Newsgroups: comp.sources.misc
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Subject: v09i036: "ed" clone
- Reply-To: unknown@unknown.UUCP (Ian Phillipps)
-
- Posting-number: Volume 9, Issue 36
- Submitted-by: unknown@unknown.UUCP (Ian Phillipps)
- Archive-name: ed_ip
-
- [Attributions and addresses lost -- please don't send compressed tar files
- without prior arrangement! ++bsa]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: ed.c ed.man read.me
- # Wrapped by allbery@uunet on Sun Nov 26 15:38:36 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'ed.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ed.c'\"
- else
- echo shar: Extracting \"'ed.c'\" \(27843 characters\)
- sed "s/^X//" >'ed.c' <<'END_OF_FILE'
- X/*
- X * ed - standard editor
- X * ~~
- X * Authors: Brian Beattie, Kees Bot, and others
- X *
- X * Copyright 1987 Brian Beattie Rights Reserved.
- X * Permission to copy or distribute granted under the following conditions:
- X * 1). No charge may be made other than reasonable charges for reproduction.
- X * 2). This notice must remain intact.
- X * 3). No further restrictions may be added.
- X * 4). Except meaningless ones.
- X *
- X * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- X * TurboC mods and cleanup 8/17/88 RAMontante.
- X * Further information (posting headers, etc.) at end of file.
- X * RE stuff replaced with Spencerian version, sundry other bugfix+speedups
- X * Ian Phillipps. Version incremented to "5".
- X * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
- X */
- X
- Xint version = 5; /* used only in the "set" function, for i.d. */
- X
- X#include <stdio.h>
- X/* Regexp is Henry Spencer's package. WARNING: regsub is modified to return
- X * a pointer to the \0 after the destination string, and this program refers
- X * to the "private" reganch field in the struct regexp.
- X */
- X#include <regexp.h>
- X
- X#ifdef __TURBOC__
- X#include <stdlib.h>
- X#include <signal.h>
- X#include <string.h>
- X#include <ctype.h>
- X#include <io.h>
- X
- X#define _cleanup() ;
- X
- X#endif /* ifdef __TURBOC__ */
- X
- X
- X/*
- X * #defines for non-printing ASCII characters
- X */
- X#define NUL 0x00 /* ^@ */
- X#define EOS 0x00 /* end of string */
- X#define SOH 0x01 /* ^A */
- X#define STX 0x02 /* ^B */
- X#define ETX 0x03 /* ^C */
- X#define EOT 0x04 /* ^D */
- X#define ENQ 0x05 /* ^E */
- X#define ACK 0x06 /* ^F */
- X#define BEL 0x07 /* ^G */
- X#define BS 0x08 /* ^H */
- X#define HT 0x09 /* ^I */
- X#define LF 0x0a /* ^J */
- X#define NL '\n'
- X#define VT 0x0b /* ^K */
- X#define FF 0x0c /* ^L */
- X#define CR 0x0d /* ^M */
- X#define SO 0x0e /* ^N */
- X#define SI 0x0f /* ^O */
- X#define DLE 0x10 /* ^P */
- X#define DC1 0x11 /* ^Q */
- X#define DC2 0x12 /* ^R */
- X#define DC3 0x13 /* ^S */
- X#define DC4 0x14 /* ^T */
- X#define NAK 0x15 /* ^U */
- X#define SYN 0x16 /* ^V */
- X#define ETB 0x17 /* ^W */
- X#define CAN 0x18 /* ^X */
- X#define EM 0x19 /* ^Y */
- X#define SUB 0x1a /* ^Z */
- X#define ESC 0x1b /* ^[ */
- X#define FS 0x1c /* ^\ */
- X#define GS 0x1d /* ^] */
- X#define RS 0x1e /* ^^ */
- X#define US 0x1f /* ^_ */
- X#define SP 0x20 /* space */
- X#define DEL 0x7f /* DEL*/
- X#define ESCAPE '\\'
- X
- X
- X#define TRUE 1
- X#define FALSE 0
- X#define ERR -2
- X#define FATAL (ERR-1)
- X#define CHANGED (ERR-2)
- X#define SET_FAIL (ERR-3)
- X#define SUB_FAIL (ERR-4)
- X#define MEM_FAIL (ERR-5)
- X
- X
- X#define BUFFER_SIZE 2048 /* stream-buffer size: == 1 hd cluster */
- X
- X#define LINFREE 1 /* entry not in use */
- X#define LGLOB 2 /* line marked global */
- X
- X#define MAXLINE 512 /* max number of chars per line */
- X#define MAXPAT 256 /* max number of chars per replacement pattern */
- X#define MAXFNAME 256 /* max file name size */
- X
- X
- X/** Global variables **/
- X
- Xstruct line {
- X int l_stat; /* empty, mark */
- X struct line *l_prev;
- X struct line *l_next;
- X char l_buff[1];
- X};
- Xtypedef struct line LINE;
- X
- X
- Xint diag = 1; /* diagnostic-output? flag */
- Xint truncflg = 1; /* truncate long line flag */
- Xint eightbit = 1; /* save eighth bit */
- Xint nonascii; /* count of non-ascii chars read */
- Xint nullchar; /* count of null chars read */
- Xint truncated; /* count of lines truncated */
- Xchar fname[MAXFNAME];
- Xint fchanged; /* file-changed? flag */
- Xint nofname;
- Xint mark['z'-'a'+1];
- Xregexp *oldpat;
- X
- XLINE Line0;
- Xint CurLn = 0;
- XLINE *CurPtr = &Line0; /* CurLn and CurPtr must be kept in step */
- Xint LastLn = 0;
- Xchar inlin[MAXLINE];
- Xint pflag;
- Xint Line1, Line2, nlines;
- Xint nflg; /* print line number flag */
- Xint lflg; /* print line in verbose mode */
- Xint pflg; /* print current line after each command */
- Xchar *inptr; /* tty input buffer */
- X
- Xstruct tbl {
- X char *t_str;
- X int *t_ptr;
- X int t_val;
- X} *t, tbl[] = {
- X "number", &nflg, TRUE,
- X "nonumber", &nflg, FALSE,
- X "list", &lflg, TRUE,
- X "nolist", &lflg, FALSE,
- X "eightbit", &eightbit, TRUE,
- X "noeightbit", &eightbit, FALSE,
- X 0
- X};
- X
- X
- X/*-------------------------------------------------------------------------*/
- X
- X#ifdef __TURBOC__ /* prototypes (unneeded?) */
- X
- Xvoid prntln(char *, int, int);
- Xvoid putcntl(char , FILE *);
- Xint doprnt(int, int);
- XLINE *getptr(int);
- Xint del(int, int);
- Xint ins(char *);
- Xint append(int, int);
- Xint deflt(int, int);
- Xregexp *optpat(void);
- Xint egets( char*, int, FILE* );
- Xint ckglob( void );
- Xint doglob( void );
- Xint docmd( int );
- Xint dolst( int, int );
- Xint doread( int, char* );
- Xint dowrite( int, int, char*, int );
- Xint find( regexp*, int );
- Xchar* getfn( void );
- Xint getlst( void );
- Xint getnum( int );
- Xint getone( void );
- Xint getrhs( char* );
- Xint join( int, int );
- Xint move( int );
- Xint set( void );
- Xint subst( regexp*, char*, int, int );
- Xint transfer( int );
- X
- X#else /* !__TURBOC__ */
- X
- Xextern char *strcpy();
- Xextern int *malloc();
- Xextern LINE *getptr();
- Xextern char *gettxt();
- Xextern char *gettxtl();
- Xextern char *catsub();
- Xregexp *optpat();
- X
- X#endif /* __TURBOC__ */
- X
- X
- X/*________ Macros ________________________________________________________*/
- X
- X#ifndef max
- X# define max(a,b) ((a) > (b) ? (a) : (b))
- X#endif
- X
- X#ifndef min
- X# define min(a,b) ((a) < (b) ? (a) : (b))
- X#endif
- X
- X#ifndef toupper
- X# define toupper(c) ((c >= 'a' && c <= 'z') ? c-32 : c )
- X#endif
- X
- X#define nextln(l) ((l)+1 > LastLn ? 0 : (l)+1)
- X#define prevln(l) ((l)-1 < 0 ? LastLn : (l)-1)
- X
- X#define gettxtl(lin) ((lin)->l_buff)
- X#define gettxt(num) (gettxtl( getptr(num) ))
- X
- X#define getnextptr(p) ((p)->l_next)
- X#define getprevptr(p) ((p)->l_prev)
- X
- X#define setCurLn( lin ) ( CurPtr = getptr( CurLn = (lin) ) )
- X#define nextCurLn() ( CurLn = nextln(CurLn), CurPtr = getnextptr( CurPtr ) )
- X#define prevCurLn() ( CurLn = prevln(CurLn), CurPtr = getprevptr( CurPtr ) )
- X
- X#define clrbuf() del(1, LastLn)
- X
- X#define Skip_White_Space {while (*inptr==SP || *inptr==HT) inptr++;}
- X
- X#define relink(a, x, y, b) { (x)->l_prev = (a); (y)->l_next = (b); }
- X
- X
- X/*________ functions ______________________________________________________*/
- X
- X
- X/* append.c */
- X
- Xappend(line, glob)
- Xint line, glob;
- X{
- X char lin[MAXLINE];
- X
- X if(glob)
- X return(ERR);
- X setCurLn( line );
- X for (;;) {
- X char *p = lin;
- X if(nflg)
- X printf("%6d. ",CurLn+1);
- X while( p < &lin[ MAXLINE ] ) {
- X int ch = getchar();
- X if( ch == EOF )
- X return EOF;
- X if( ch == '\n' ) {
- X *p = EOS; break;
- X }
- X *p++ = ch;
- X }
- X if(lin[0] == '.' && lin[1] == '\0')
- X return(0);
- X if( ins(lin) < 0)
- X return( MEM_FAIL );
- X }
- X}
- X
- X/* ckglob.c */
- X
- Xckglob()
- X{
- X regexp *glbpat;
- X char c, delim, *lin;
- X int num;
- X LINE *ptr;
- X
- X c = *inptr;
- X
- X if(c != 'g' && c != 'v')
- X return(0);
- X if (deflt(1, LastLn) < 0)
- X return(ERR);
- X
- X delim = *++inptr;
- X if(delim <= ' ')
- X return(ERR);
- X
- X glbpat = optpat();
- X if(*inptr == delim)
- X inptr++;
- X ptr = getptr(1);
- X for (num=1; num<=LastLn; num++) {
- X ptr->l_stat &= ~LGLOB;
- X if (Line1 <= num && num <= Line2) {
- X lin = gettxtl(ptr);
- X if(regexec(glbpat, lin )) {
- X if (c=='g') ptr->l_stat |= LGLOB;
- X } else {
- X if (c=='v') ptr->l_stat |= LGLOB;
- X }
- X ptr = getnextptr(ptr);
- X }
- X }
- X return(1);
- X}
- X
- X
- X/* deflt.c
- X * Set Line1 & Line2 (the command-range delimiters) if the file is
- X * empty; Test whether they have valid values.
- X */
- X
- Xint deflt(def1, def2)
- Xint def1, def2;
- X{
- X if(nlines == 0) {
- X Line1 = def1;
- X Line2 = def2;
- X }
- X return ( (Line1>Line2 || Line1<=0) ? ERR : 0 );
- X}
- X
- X
- X/* del.c */
- X
- X/* One of the calls to this function tests its return value for an error
- X * condition. But del doesn't return any error value, and it isn't obvious
- X * to me what errors might be detectable/reportable. To silence a warning
- X * message, I've added a constant return statement. -- RAM
- X * ... It could check to<=LastLn ... igp
- X */
- X
- Xdel(from, to)
- Xint from, to;
- X{
- X LINE *first, *last, *next, *tmp;
- X
- X if(from < 1)
- X from = 1;
- X first = getprevptr( getptr( from ) );
- X last = getnextptr( getptr( to ) );
- X next = first->l_next;
- X while(next != last && next != &Line0) {
- X tmp = next->l_next;
- X free(next);
- X next = tmp;
- X }
- X relink(first, last, first, last);
- X LastLn -= (to - from)+1;
- X setCurLn( prevln(from) );
- X return(0);
- X}
- X
- X
- Xint dolst(line1, line2)
- Xint line1, line2;
- X{
- X int oldlflg=lflg, p;
- X
- X lflg = 1;
- X p = doprnt(line1, line2);
- X lflg = oldlflg;
- X return p;
- X}
- X
- X
- X/* esc.c
- X * Map escape sequences into their equivalent symbols. Returns the
- X * correct ASCII character. If no escape prefix is present then s
- X * is untouched and *s is returned, otherwise **s is advanced to point
- X * at the escaped character and the translated character is returned.
- X */
- Xesc(s)
- Xchar **s;
- X{
- X register int rval;
- X
- X if (**s != ESCAPE) {
- X rval = **s;
- X } else {
- X (*s)++;
- X switch(toupper(**s)) {
- X case '\000':
- X rval = ESCAPE; break;
- X case 'S':
- X rval = ' '; break;
- X case 'N':
- X rval = '\n'; break;
- X case 'T':
- X rval = '\t'; break;
- X case 'B':
- X rval = '\b'; break;
- X case 'R':
- X rval = '\r'; break;
- X default:
- X rval = **s; break;
- X }
- X }
- X return (rval);
- X}
- X
- X
- X/* doprnt.c */
- X
- Xint doprnt(from, to)
- Xint from, to;
- X{
- X from = (from < 1) ? 1 : from;
- X to = (to > LastLn) ? LastLn : to;
- X
- X if(to != 0) {
- X setCurLn( from );
- X while( CurLn <= to ) {
- X prntln( gettxtl( CurPtr ), lflg, (nflg ? CurLn : 0));
- X if( CurLn == to )
- X break;
- X nextCurLn();
- X }
- X }
- X return(0);
- X}
- X
- X
- Xvoid prntln(str, vflg, lin)
- Xchar *str;
- Xint vflg, lin;
- X{
- X if(lin)
- X printf("%7d ",lin);
- X while(*str && *str != NL) {
- X if(*str < ' ' || *str >= 0x7f) {
- X switch(*str) {
- X case '\t':
- X if(vflg)
- X putcntl(*str, stdout);
- X else
- X putc(*str, stdout);
- X break;
- X
- X case DEL:
- X putc('^', stdout);
- X putc('?', stdout);
- X break;
- X
- X default:
- X putcntl(*str, stdout);
- X break;
- X }
- X } else
- X putc(*str, stdout);
- X str++;
- X }
- X if(vflg)
- X putchar('$');
- X putchar('\n');
- X}
- X
- X
- Xvoid putcntl(c, stream)
- Xchar c;
- XFILE *stream;
- X{
- X putc('^', stream);
- X putc((c&31)|'@', stream);
- X}
- X
- X
- X/* egets.c */
- X
- Xegets(str,size,stream)
- Xchar *str;
- Xint size;
- XFILE *stream;
- X{
- X int c, count;
- X char *cp;
- X
- X for(count = 0, cp = str; size > count;) {
- X c = getc(stream);
- X if(c == EOF) {
- X *cp = EOS;
- X if(count)
- X puts("[Incomplete last line]");
- X return(count);
- X }
- X else if(c == NL) {
- X *cp = EOS;
- X return(++count);
- X }
- X else if (c == 0)
- X nullchar++; /* count nulls */
- X else {
- X if(c > 127) {
- X if(!eightbit) /* if not saving eighth bit */
- X c = c&127; /* strip eigth bit */
- X nonascii++; /* count it */
- X }
- X *cp++ = c; /* not null, keep it */
- X count++;
- X }
- X }
- X str[count-1] = EOS;
- X if(c != NL) {
- X puts("truncating line");
- X truncated++;
- X while((c = getc(stream)) != EOF)
- X if(c == NL)
- X break;
- X }
- X return(count);
- X} /* egets */
- X
- X
- Xdoread(lin, fname)
- Xint lin;
- Xchar *fname;
- X{
- X FILE *fp;
- X int err;
- X unsigned long bytes;
- X unsigned int lines;
- X static char str[MAXLINE];
- X
- X err = 0;
- X nonascii = nullchar = truncated = 0;
- X
- X if (diag) printf("\"%s\" ",fname);
- X if( (fp = fopen(fname, "r")) == NULL ) {
- X puts(" isn't readable.");
- X return( ERR );
- X }
- X setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
- X setCurLn( lin );
- X for(lines = 0, bytes = 0;(err = egets(str,MAXLINE,fp)) > 0;) {
- X bytes += err;
- X if(ins(str) < 0) {
- X err = MEM_FAIL;
- X break;
- X }
- X lines++;
- X }
- X fclose(fp);
- X if(err < 0)
- X return(err);
- X if (diag) {
- X printf("%u lines %u bytes",lines,bytes);
- X if(nonascii)
- X printf(" [%d non-ascii]",nonascii);
- X if(nullchar)
- X printf(" [%d nul]",nullchar);
- X if(truncated)
- X printf(" [%d lines truncated]",truncated);
- X putchar('\n');
- X }
- X return( err );
- X} /* doread */
- X
- X
- Xint dowrite(from, to, fname, apflg)
- Xint from, to;
- Xchar *fname;
- Xint apflg;
- X{
- X FILE *fp;
- X int lin, err;
- X unsigned int lines;
- X unsigned long bytes;
- X char *str;
- X LINE *lptr;
- X
- X err = 0;
- X lines = bytes = 0;
- X
- X printf("\"%s\" ",fname);
- X if((fp = fopen(fname,(apflg?"a":"w"))) == NULL) {
- X puts(" can't be opened for writing!");
- X return( ERR );
- X }
- X
- X setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
- X lptr = getptr(from);
- X for(lin = from; lin <= to; lin++) {
- X str = lptr->l_buff;
- X lines++;
- X bytes += strlen(str) + 1; /* str + '\n' */
- X if(fputs(str, fp) == EOF) {
- X puts("file write error");
- X err++;
- X break;
- X }
- X fputc('\n', fp);
- X lptr = lptr->l_next;
- X }
- X printf("%u lines %lu bytes\n",lines,bytes);
- X fclose(fp);
- X return( err );
- X} /* dowrite */
- X
- X
- X/* find.c */
- X
- Xfind(pat, dir)
- Xregexp *pat;
- Xint dir;
- X{
- X int i, num;
- X LINE *lin;
- X
- X num = CurLn;
- X lin = CurPtr;
- X for(i=0; i<LastLn; i++ ) {
- X if(regexec( pat, gettxtl( lin ) ))
- X return(num);
- X if( dir )
- X num = nextln(num), lin = getnextptr(lin);
- X else
- X num = prevln(num), lin = getprevptr(lin);
- X }
- X return ( ERR );
- X}
- X
- X
- X/* getfn.c */
- X
- Xchar *getfn()
- X{
- X static char file[256];
- X char *cp;
- X
- X if(*inptr == NL) {
- X nofname=TRUE;
- X strcpy(file, fname);
- X } else {
- X nofname=FALSE;
- X Skip_White_Space;
- X
- X cp = file;
- X while(*inptr && *inptr != NL && *inptr != SP && *inptr != HT)
- X *cp++ = *inptr++;
- X *cp = '\0';
- X
- X if(strlen(file) == 0) {
- X puts("bad file name");
- X return( NULL );
- X }
- X }
- X
- X if(strlen(file) == 0) {
- X puts("no file name");
- X return(NULL);
- X }
- X return( file );
- X} /* getfn */
- X
- X
- Xint getnum(first)
- Xint first;
- X{
- X regexp *srchpat;
- X int num;
- X char c;
- X
- X Skip_White_Space;
- X
- X if(*inptr >= '0' && *inptr <= '9') { /* line number */
- X for(num = 0; *inptr >= '0' && *inptr <= '9'; ++inptr) {
- X num = (num * 10) + (*inptr - '0');
- X }
- X return num;
- X }
- X
- X switch(c = *inptr) {
- X case '.':
- X inptr++;
- X return (CurLn);
- X
- X case '$':
- X inptr++;
- X return (LastLn);
- X
- X case '/':
- X case '?':
- X srchpat = optpat();
- X if(*inptr == c)
- X *inptr++;
- X return(find(srchpat,c == '/'?1:0));
- X
- X case '-':
- X case '+':
- X return(first ? CurLn : 1);
- X
- X case '\'':
- X inptr++;
- X if (*inptr < 'a' || *inptr > 'z')
- X return(EOF);
- X return mark[ *inptr++ - 'a' ];
- X
- X default:
- X return ( first ? EOF : 1 ); /* unknown address */
- X }
- X} /* getnum */
- X
- X
- X/* getone.c
- X * Parse a number (or arithmetic expression) off the command line.
- X */
- X#define FIRST 1
- X#define NOTFIRST 0
- X
- Xint getone()
- X{
- X int c, i, num;
- X
- X if((num = getnum(FIRST)) >= 0) {
- X for (;;) {
- X Skip_White_Space;
- X if(*inptr != '+' && *inptr != '-')
- X break; /* exit infinite loop */
- X
- X c = *inptr++;
- X if((i = getnum(NOTFIRST)) < 0)
- X return ( i );
- X if(c == '+')
- X num += i;
- X else
- X num -= i;
- X }
- X }
- X return ( num>LastLn ? ERR : num );
- X} /* getone */
- X
- X
- Xgetlst()
- X{
- X int num;
- X
- X Line2 = 0;
- X for(nlines = 0; (num = getone()) >= 0;)
- X {
- X Line1 = Line2;
- X Line2 = num;
- X nlines++;
- X if(*inptr != ',' && *inptr != ';')
- X break;
- X if(*inptr == ';')
- X setCurLn( num );
- X inptr++;
- X }
- X nlines = min(nlines, 2);
- X if(nlines == 0)
- X Line2 = CurLn;
- X if(nlines <= 1)
- X Line1 = Line2;
- X
- X return ( (num == ERR) ? num : nlines );
- X} /* getlst */
- X
- X
- X/* getptr.c */
- X
- XLINE *getptr(num)
- Xint num;
- X{
- X LINE *ptr;
- X int j;
- X
- X if (2*num>LastLn && num<=LastLn) { /* high line numbers */
- X ptr = Line0.l_prev;
- X for (j = LastLn; j>num; j--)
- X ptr = ptr->l_prev;
- X } else { /* low line numbers */
- X ptr = &Line0;
- X for(j = 0; j < num; j++)
- X ptr = ptr->l_next;
- X }
- X return(ptr);
- X}
- X
- X
- X/* getrhs.c */
- X
- Xint getrhs(sub)
- Xchar *sub;
- X{
- X char delim = *inptr++;
- X char *outmax = sub + MAXPAT;
- X if( delim == NL || *inptr == NL) /* check for eol */
- X return( ERR );
- X while( *inptr != delim && *inptr != NL ) {
- X if ( sub > outmax )
- X return ERR;
- X if ( *inptr == ESCAPE ) {
- X switch ( *++inptr ) {
- X case 'r':
- X *sub++ = '\r';
- X inptr++;
- X break;
- X case ESCAPE:
- X *sub++ = ESCAPE;
- X *sub++ = ESCAPE;
- X inptr++;
- X case 'n':
- X *sub++ = '\n';
- X inptr++;
- X break;
- X case 'b':
- X *sub++ = '\b';
- X inptr++;
- X break;
- X case '0': {
- X int i=3;
- X *sub = 0;
- X do {
- X if (*++inptr<'0' || *inptr >'7')
- X break;
- X *sub = (*sub<<3) | (*inptr-'0');
- X } while (--i!=0);
- X sub++;
- X } break;
- X default:
- X if ( *inptr != delim )
- X *sub++ = ESCAPE;
- X *sub++ = *inptr;
- X if ( *inptr != NL )
- X inptr++;
- X }
- X }
- X else *sub++ = *inptr++;
- X }
- X *sub = '\0';
- X
- X inptr++; /* skip over delimter */
- X Skip_White_Space;
- X if(*inptr == 'g') {
- X *inptr++;
- X return( 1 );
- X }
- X return( 0 );
- X}
- X
- X/* ins.c */
- X
- Xins(str)
- Xchar *str;
- X{
- X char *cp;
- X LINE *new, *nxt;
- X int len;
- X
- X do {
- X for ( cp = str; *cp && *cp != NL; cp++ )
- X ;
- X len = cp - str;
- X /* cp now points to end of first or only line */
- X
- X if((new = (LINE *)malloc(sizeof(LINE)+len)) == NULL)
- X return( MEM_FAIL ); /* no memory */
- X
- X new->l_stat=0;
- X strncpy(new->l_buff,str,len); /* build new line */
- X new->l_buff[len] = EOS;
- X nxt = getnextptr(CurPtr); /* get next line */
- X relink(CurPtr, new, new, nxt); /* add to linked list */
- X relink(new, nxt, CurPtr, new);
- X LastLn++;
- X CurLn++;
- X CurPtr = new;
- X str = cp + 1;
- X }
- X while( *cp != EOS );
- X return 1;
- X}
- X
- X
- X/* join.c */
- X
- Xint join(first, last)
- Xint first, last;
- X{
- X char buf[MAXLINE];
- X char *cp=buf, *str;
- X LINE *lin;
- X int num;
- X
- X if (first<=0 || first>last || last>LastLn)
- X return(ERR);
- X if (first==last) {
- X setCurLn( first );
- X return 0;
- X }
- X lin = getptr(first);
- X for (num=first; num<=last; num++) {
- X str=gettxtl(lin);
- X while ( *str ) {
- X if (cp >= buf + MAXLINE-1 ) {
- X puts("line too long");
- X return(ERR);
- X }
- X *cp++ = *str++;
- X }
- X lin = getnextptr(lin);
- X }
- X *cp = EOS;
- X del(first, last);
- X if( ins(buf) < 0 )
- X return MEM_FAIL;
- X fchanged = TRUE;
- X return 0;
- X}
- X
- X
- X/* move.c
- X * Unlink the block of lines from Line1 to Line2, and relink them
- X * after line "num".
- X */
- X
- Xint move(num)
- Xint num;
- X{
- X int range;
- X LINE *before, *first, *last, *after;
- X
- X if( Line1 <= num && num <= Line2 )
- X return( ERR );
- X range = Line2 - Line1 + 1;
- X before = getptr(prevln(Line1));
- X first = getptr(Line1);
- X last = getptr(Line2);
- X after = getptr(nextln(Line2));
- X
- X relink(before, after, before, after);
- X LastLn -= range; /* per AST's posted patch 2/2/88 */
- X if (num > Line1)
- X num -= range;
- X
- X before = getptr(num);
- X after = getptr(nextln(num));
- X relink(before, first, last, after);
- X relink(last, after, before, first);
- X LastLn += range; /* per AST's posted patch 2/2/88 */
- X setCurLn( num + range );
- X return( 1 );
- X}
- X
- X
- Xint transfer(num)
- Xint num;
- X{
- X int mid, lin, ntrans;
- X
- X if (Line1<=0 || Line1>Line2)
- X return(ERR);
- X
- X mid= num<Line2 ? num : Line2;
- X
- X setCurLn( num );
- X ntrans=0;
- X
- X for (lin=Line1; lin<=mid; lin++) {
- X if( ins(gettxt(lin)) < 0 )
- X return MEM_FAIL;
- X ntrans++;
- X }
- X lin+=ntrans;
- X Line2+=ntrans;
- X
- X for ( ; lin <= Line2; lin += 2 ) {
- X if( ins(gettxt(lin)) < 0 )
- X return MEM_FAIL;
- X Line2++;
- X }
- X return(1);
- X}
- X
- X
- X/* optpat.c */
- X
- Xregexp *optpat(void)
- X{
- X char delim, str[MAXPAT], *cp;
- X
- X delim = *inptr++;
- X cp = str;
- X while(*inptr != delim && *inptr != NL) {
- X if(*inptr == ESCAPE && inptr[1] != NL)
- X *cp++ = *inptr++;
- X *cp++ = *inptr++;
- X }
- X
- X *cp = EOS;
- X if(*str == EOS)
- X return(oldpat);
- X if(oldpat)
- X free(oldpat);
- X return oldpat = regcomp(str);
- X}
- X
- X/* regerror.c */
- Xvoid regerror( char *s )
- X{
- X fprintf( stderr, "ed: %s\n", s );
- X}
- X
- X
- Xset()
- X{
- X char word[16];
- X int i;
- X
- X if(*(++inptr) != 't') {
- X if(*inptr != SP && *inptr != HT && *inptr != NL)
- X return(ERR);
- X } else
- X inptr++;
- X
- X if ( (*inptr == NL)
- X#ifdef __TURBOC__
- X || (*inptr == CR)
- X#endif
- X )
- X {
- X printf("ed version %d.%d\n", version/100, version%100);
- X printf( "number %s, list %s\n",
- X nflg?"ON":"OFF",
- X lflg?"ON":"OFF");
- X return(0);
- X }
- X
- X Skip_White_Space;
- X for(i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
- X word[i++] = *inptr++;
- X word[i] = EOS;
- X for(t = tbl; t->t_str; t++) {
- X if(strcmp(word,t->t_str) == 0) {
- X *t->t_ptr = t->t_val;
- X return(0);
- X }
- X }
- X return SET_FAIL;
- X}
- X
- X#ifndef relink
- Xvoid relink(a, x, y, b)
- XLINE *a, *x, *y, *b;
- X{
- X x->l_prev = a;
- X y->l_next = b;
- X}
- X#endif
- X
- X
- Xvoid set_ed_buf(void)
- X{
- X relink(&Line0, &Line0, &Line0, &Line0);
- X CurLn = LastLn = 0;
- X CurPtr = &Line0;
- X}
- X
- X
- X/* subst.c */
- X
- Xint subst(pat, sub, gflg, pflag)
- Xregexp *pat;
- Xchar *sub;
- Xint gflg, pflag;
- X{
- X int nchngd = 0;
- X char *txtptr;
- X char *new, buf[MAXLINE];
- X int still_running = 1;
- X LINE *lastline = getptr( Line2 );
- X
- X if(Line1 <= 0)
- X return( SUB_FAIL );
- X nchngd = 0; /* reset count of lines changed */
- X
- X for( setCurLn( prevln( Line1 ) ); still_running; ) {
- X nextCurLn();
- X new = buf;
- X if ( CurPtr == lastline )
- X still_running = 0;
- X if ( regexec( pat, txtptr = gettxtl( CurPtr ) ) ) {
- X do
- X {
- X /* Copy leading text */
- X int diff = pat->startp[0] - txtptr;
- X strncpy( new, txtptr, diff );
- X new += diff;
- X /* Do substitution */
- X new = regsub( pat, sub, new );
- X txtptr = pat->endp[0];
- X }
- X while( gflg && !pat->reganch && regexec( pat, txtptr ));
- X
- X /* Copy trailing chars */
- X while( *txtptr ) *new++ = *txtptr++;
- X
- X if(new >= buf+MAXLINE)
- X return( SUB_FAIL );
- X *new++ = EOS;
- X del(CurLn,CurLn);
- X if( ins(buf) < 0 )
- X return MEM_FAIL;
- X nchngd++;
- X if(pflag)
- X doprnt(CurLn, CurLn);
- X }
- X }
- X return (( nchngd == 0 && !gflg ) ? SUB_FAIL : nchngd);
- X}
- X
- X
- X/* system.c */
- X#ifndef __TURBOC__
- X
- X#define SHELL "/bin/sh"
- X
- Xsystem(c)
- Xchar *c; {
- X int pid, status;
- X
- X switch (pid = fork()) {
- X case -1:
- X return -1;
- X case 0:
- X execl(SHELL, "sh", "-c", c, (char *) 0);
- X exit(-1);
- X default:
- X while (wait(&status) != pid)
- X ;
- X }
- X return status;
- X}
- X#endif /* ifndef __TURBOC__ */
- X
- X
- X/* docmd.c
- X * Perform the command specified in the input buffer, as pointed to
- X * by inptr. Actually, this finds the command letter first.
- X */
- X
- Xint docmd(glob)
- Xint glob;
- X{
- X static char rhs[MAXPAT];
- X regexp *subpat;
- X int c, err, line3;
- X int apflg, pflag, gflag;
- X int nchng;
- X char *fptr;
- X
- X pflag = FALSE;
- X Skip_White_Space;
- X
- X c = *inptr++;
- X switch(c) {
- X case NL:
- X if( nlines == 0 && (Line2 = nextln(CurLn)) == 0 )
- X return(ERR);
- X setCurLn( Line2 );
- X return (1);
- X
- X case '=':
- X printf("%d\n",Line2);
- X break;
- X
- X case 'a':
- X if(*inptr != NL || nlines > 1)
- X return(ERR);
- X
- X if(append(Line1, glob) < 0)
- X return(ERR);
- X fchanged = TRUE;
- X break;
- X
- X case 'c':
- X if(*inptr != NL)
- X return(ERR);
- X
- X if(deflt(CurLn, CurLn) < 0)
- X return(ERR);
- X
- X if(del(Line1, Line2) < 0)
- X return(ERR);
- X if(append(CurLn, glob) < 0)
- X return(ERR);
- X fchanged = TRUE;
- X break;
- X
- X case 'd':
- X if(*inptr != NL)
- X return(ERR);
- X
- X if(deflt(CurLn, CurLn) < 0)
- X return(ERR);
- X
- X if(del(Line1, Line2) < 0)
- X return(ERR);
- X if(nextln(CurLn) != 0)
- X nextCurLn();
- X fchanged = TRUE;
- X break;
- X
- X case 'e':
- X if(nlines > 0)
- X return(ERR);
- X if(fchanged)
- X return CHANGED;
- X /*FALL THROUGH*/
- X case 'E':
- X if(nlines > 0)
- X return(ERR);
- X
- X if(*inptr != ' ' && *inptr != HT && *inptr != NL)
- X return(ERR);
- X
- X if((fptr = getfn()) == NULL)
- X return(ERR);
- X
- X clrbuf();
- X if((err = doread(0, fptr)) < 0)
- X return(err);
- X
- X strcpy(fname, fptr);
- X fchanged = FALSE;
- X break;
- X
- X case 'f':
- X if(nlines > 0)
- X return(ERR);
- X
- X if(*inptr != ' ' && *inptr != HT && *inptr != NL)
- X return(ERR);
- X
- X if((fptr = getfn()) == NULL)
- X return(ERR);
- X
- X if (nofname)
- X printf("%s\n", fname);
- X else
- X strcpy(fname, fptr);
- X break;
- X
- X case 'i':
- X if(*inptr != NL || nlines > 1)
- X return(ERR);
- X
- X if(append(prevln(Line1), glob) < 0)
- X return(ERR);
- X fchanged = TRUE;
- X break;
- X
- X case 'j':
- X if (*inptr != NL || deflt(CurLn, CurLn+1)<0)
- X return(ERR);
- X
- X if (join(Line1, Line2) < 0)
- X return(ERR);
- X break;
- X
- X case 'k':
- X Skip_White_Space;
- X
- X if (*inptr < 'a' || *inptr > 'z')
- X return ERR;
- X c= *inptr++;
- X
- X if(*inptr != ' ' && *inptr != HT && *inptr != NL)
- X return(ERR);
- X
- X mark[c-'a'] = Line1;
- X break;
- X
- X case 'l':
- X if(*inptr != NL)
- X return(ERR);
- X if(deflt(CurLn,CurLn) < 0)
- X return(ERR);
- X if (dolst(Line1,Line2) < 0)
- X return(ERR);
- X break;
- X
- X case 'm':
- X if((line3 = getone()) < 0)
- X return(ERR);
- X if(deflt(CurLn,CurLn) < 0)
- X return(ERR);
- X if(move(line3) < 0)
- X return(ERR);
- X fchanged = TRUE;
- X break;
- X
- X case 'P':
- X case 'p':
- X if(*inptr != NL)
- X return(ERR);
- X if(deflt(CurLn,CurLn) < 0)
- X return(ERR);
- X if(doprnt(Line1,Line2) < 0)
- X return(ERR);
- X break;
- X
- X case 'q':
- X if(fchanged)
- X return CHANGED;
- X /*FALL THROUGH*/
- X case 'Q':
- X if(*inptr == NL && nlines == 0 && !glob)
- X return(EOF);
- X else
- X return(ERR);
- X
- X case 'r':
- X if(nlines > 1)
- X return(ERR);
- X
- X if(nlines == 0) /* The original code tested */
- X Line2 = LastLn; /* if(nlines = 0) */
- X /* which looks wrong. RAM */
- X
- X if(*inptr != ' ' && *inptr != HT && *inptr != NL)
- X return(ERR);
- X
- X if((fptr = getfn()) == NULL)
- X return(ERR);
- X
- X if((err = doread(Line2, fptr)) < 0)
- X return(err);
- X fchanged = TRUE;
- X break;
- X
- X case 's':
- X if(*inptr == 'e')
- X return(set());
- X Skip_White_Space;
- X if((subpat = optpat()) == NULL)
- X return(ERR);
- X if((gflag = getrhs(rhs)) < 0)
- X return(ERR);
- X if(*inptr == 'p')
- X pflag++;
- X if(deflt(CurLn, CurLn) < 0)
- X return(ERR);
- X if((nchng = subst(subpat, rhs, gflag, pflag)) < 0)
- X return(ERR);
- X if(nchng)
- X fchanged = TRUE;
- X break;
- X
- X case 't':
- X if((line3 = getone()) < 0)
- X return(ERR);
- X if(deflt(CurLn,CurLn) < 0)
- X return(ERR);
- X if(transfer(line3) < 0)
- X return(ERR);
- X fchanged = TRUE;
- X break;
- X
- X case 'W':
- X case 'w':
- X apflg = (c=='W');
- X
- X if(*inptr != ' ' && *inptr != HT && *inptr != NL)
- X return(ERR);
- X
- X if((fptr = getfn()) == NULL)
- X return(ERR);
- X
- X if(deflt(1, LastLn) < 0)
- X return(ERR);
- X if(dowrite(Line1, Line2, fptr, apflg) < 0)
- X return(ERR);
- X fchanged = FALSE;
- X break;
- X
- X case 'x':
- X if(*inptr == NL && nlines == 0 && !glob) {
- X if((fptr = getfn()) == NULL)
- X return(ERR);
- X if(dowrite(1, LastLn, fptr, 0) >= 0)
- X return(EOF);
- X }
- X return(ERR);
- X
- X case 'z':
- X if(deflt(CurLn,CurLn) < 0)
- X return(ERR);
- X
- X switch(*inptr) {
- X case '-':
- X if(doprnt(Line1-21,Line1) < 0)
- X return(ERR);
- X break;
- X
- X case '.':
- X if(doprnt(Line1-11,Line1+10) < 0)
- X return(ERR);
- X break;
- X
- X case '+':
- X case '\n':
- X if(doprnt(Line1,Line1+21) < 0)
- X return(ERR);
- X break;
- X }
- X break;
- X
- X default:
- X return(ERR);
- X }
- X return (0);
- X} /* docmd */
- X
- X
- X/* doglob.c */
- Xdoglob()
- X{
- X int lin, stat;
- X char *cmd;
- X LINE *ptr;
- X
- X cmd = inptr;
- X
- X for (;;) {
- X ptr = getptr(1);
- X for (lin=1; lin<=LastLn; lin++) {
- X if (ptr->l_stat & LGLOB)
- X break;
- X ptr = getnextptr(ptr);
- X }
- X if (lin > LastLn)
- X break;
- X
- X ptr->l_stat &= ~LGLOB;
- X CurLn = lin; CurPtr = ptr;
- X inptr = cmd;
- X if((stat = getlst()) < 0)
- X return(stat);
- X if((stat = docmd(1)) < 0)
- X return(stat);
- X }
- X return(CurLn);
- X} /* doglob */
- X
- X
- X/*
- X * Software signal 2 or SIGINT is caught and the result is to resume
- X * the main loop at a command prompt.
- X */
- X#include <setjmp.h>
- Xjmp_buf env;
- X
- X#ifndef __TURBOC__
- Xintr()
- X{
- X puts("intr()?");
- X longjmp(env, 1);
- X}
- X
- X#else
- X
- Xvoid Catcher(void)
- X{
- X longjmp(env, 1);
- X}
- X#endif /* !__TURBOC__ */
- X
- X
- X/*-------- main ---------------------------------------------------------*/
- X#ifndef _Cdecl
- X# define _Cdecl
- X#endif
- X
- Xvoid _Cdecl main(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X int stat, i, doflush;
- X
- X set_ed_buf();
- X doflush=isatty(1);
- X
- X if (argc>1 && argv[1][0]=='-' && argv[1][1]==0) {
- X diag = 0;
- X argc--;
- X argv++;
- X }
- X if(argc > 1) {
- X for(i = 1; i < argc; i++) {
- X if(doread(0,argv[i])==0) {
- X setCurLn( 1 );
- X strcpy(fname, argv[i]);
- X break;
- X }
- X }
- X }
- X
- X for (;;) {
- X
- X setjmp(env);
- X putchar(':'); /* The command-line prompt */
- X
- X#ifndef __TURBOC__
- X signal(2, intr);
- X#else /* __TURBOC__ */
- X signal(SIGINT, Catcher);
- X#endif /* !__TURBOC__ */
- X
- X if (doflush)
- X fflush(stdout);
- X if (fgets(inlin, sizeof(inlin),stdin) == NULL) {
- X puts("Null input.");
- X break;
- X }
- X if(*inlin == '!') {
- X for(inptr = inlin; *inptr != NL; inptr++)
- X ;
- X *inptr = EOS;
- X system(inlin+1);
- X continue;
- X }
- X inptr = inlin;
- X if(getlst() >= 0)
- X if((stat = ckglob()) != 0) {
- X if(stat >= 0 && (stat = doglob()) >= 0) {
- X setCurLn( stat );
- X continue;
- X }
- X } else {
- X if((stat = docmd(0)) >= 0) {
- X if(stat == 1)
- X doprnt(CurLn, CurLn);
- X continue;
- X }
- X }
- X switch (stat) {
- X case EOF:
- X _cleanup(); exit(0);
- X case FATAL:
- X fputs("FATAL ERROR\n",stderr);
- X _cleanup(); exit(1);
- X case CHANGED:
- X puts("File has been changed.");
- X break;
- X case SET_FAIL:
- X puts("`set' command failed.");
- X break;
- X case SUB_FAIL:
- X puts("string substitution failed.");
- X break;
- X case MEM_FAIL:
- X puts("Out of memory: text may have been lost." );
- X break;
- X default:
- X puts("Oops?");
- X /* Unrecognized or failed command (this */
- X /* is SOOOO much better than "?" :-) */
- X }
- X }
- X} /* main */
- X/*________ end of source code ____________________________________________*/
- END_OF_FILE
- if test 27843 -ne `wc -c <'ed.c'`; then
- echo shar: \"'ed.c'\" unpacked with wrong size!
- fi
- # end of 'ed.c'
- fi
- if test -f 'ed.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ed.man'\"
- else
- echo shar: Extracting \"'ed.man'\" \(6675 characters\)
- sed "s/^X//" >'ed.man' <<'END_OF_FILE'
- Xed - line-oriented text editor, similar to UN*X V7 ed
- X
- Xsyntax:
- X ed [existing-file]
- X
- X existing-file Only an existing file can be opened. Otherwise
- X a nameless edit buffer is opened; a name can be used with
- X the `f' or `w' commands.
- X
- XAs a line editor, ed operates in one of two modes: COMMAND mode, in which
- Xa colon is displayed at the screen's bottom to prompt for a command; and
- XINPUT mode, in which all keyboard input is added to the file (edit buffer).
- XFrom COMMAND mode, INPUT mode is entered by either the `i' or `a' commands.
- XFrom INPUT mode, the COMMAND mode is restored by entering a line consisting
- Xof a single period by itself. If such a line is desired in the file, it
- Xcan be created by entering (for instance) two periods, then using the `s'
- Xcommand to change these to only one period.
- X
- XA command consists of an optional line-range specification, a single char-
- Xacter indicating the command, and for some commands an optional third
- Xargument. The line-range specification is either a single line number or
- Xa first-line number and a last-line number separated by a comma. The
- Xcharacter `^' means the first line of the file; `$' means the last line
- Xof the file.
- X
- XCommands:
- X <newline>
- X If a line is specified, make that the new current line.
- X Otherwise advance the current-line-pointer by one line.
- X = Print the line number of the current line.
- X . (by itself) Print the current line.
- X - (by itself) Move the current-line-pointer back one, and print
- X the new current line.
- X + (by itself) Move the current-line-pointer forward one, and
- X print the new current line.
- X ! Execute a shell command and return.
- X a Go into INPUT mode with a new line following the current line.
- X (INPUT mode is terminated by an input line containing only a
- X period in the first column.)
- X i Go into INPUT mode with a new line preceding the current line.
- X (INPUT mode is terminated by an input line containing only a
- X period in the first column.)
- X c Delete the specified lines (or the current line) and then
- X add new lines in their place. This is equivalent to a `d'
- X command followed by an `i' command.
- X d Delete the specified range of lines (or the current line).
- X Leave the current-line-pointer at the following line.
- X e Clear the edit buffer and begin editing a new file. This
- X command fails if the buffer contains changes (or new lines)
- X which have not been written out. To discard these changes
- X and edit a new file, use `E' instead of `e'.
- X E Clear the edit buffer and begin editing a new file, regardless
- X of any changes to the current edit buffer.
- X f Print the filename, or set it to a new name if specified.
- X g Perform the following command on all matching lines in range
- X j Join the addressed lines together (or the current line to the
- X previous line).
- X k Mark the addressed line with the specified letter. Example:
- X `17ka' puts mark "a" on line 17.
- X l List the addressed lines, showing all non-printing characters
- X and indicating the end-of-line.
- X m Move the specified range of lines to follow the line number
- X given. Example: `5,7m3' moves lines 5 through 7 "up", to
- X follow line 3.
- X p,P Print the specified lines.
- X q Quit the editor. This fails if the edit buffer contains any
- X changes. If so, use `Q' instead.
- X Q Quit the editor absolutely. Any changes are discarded.
- X r Read in a file, adding it after the current line.
- X s Substitute text on the current line. Example: `s/alpha/beta/'
- X finds the string "alpha" and replaces it with "beta".
- X t Transfer (copy) the specified range of lines to follow the line
- X number given. Example: `5,7t7' puts a copy of lines 5 through
- X 7 after line 7.
- X v Perform the following command on all non-matching lines in range
- X w,W Write the edit buffer out. If a filename is given, it is used
- X and becomes the current filename. If a range of lines is
- X specified, only those lines are written.
- X x Write the entire buffer out to its file, and terminate.
- X z Print 21 lines. `-', `.', or `+' may be given, and mean
- X "start 21 lines previous, end at current line",
- X "start 11 lines previous, end 10 lines hence", or
- X "start at current line, end 21 lines from here", respectively.
- X
- XThe syntax of g and v is <addrs> g /re/ <command>
- X
- XBUGS and COMMENTS
- X
- XThere's no "u" command. Reading files is still pretty slow. IGP.
- X
- X[Here's an example of how to split a line: .s/BUGS/BU\nGS/
- XThe backslash n (\n) ends the current line after the U and starts another
- Xline beginning with G. -Ed L]
- X
- XThe code started out as many small files. It is now one file, but the
- Xresult isn't as clean as it could be. I've cleaned it up some, but in
- Xconverting it to TurboC compliancy I've probably lost generic C compliancy.
- XHeaders describing its distribution history are appended to the code.
- X
- X[The i variable in function doprnt() has been eliminated and replaced by
- Xthe global variable CurLn. MSDOS signal code has been added to intercept
- XCTRL C and CTRL [BREAK] so that the program does not abort your work when
- Xyou press either of these key sequences. -Ed L]
- X
- XAUTHORS
- X
- XBrian Beattie seems to be the original author. Kees Bot is associated
- Xwith it. Andy Tanenbaum ported it to MINIX, and posted it to Usenet.
- XBob Montante ported it to MSDOS and did some minor dressing-up.
- XSomebody called Ed L added some comments above.
- X
- XThis version is derived from the one posted in comp.binaries.ibm.pc in ?early
- X1988.
- XIan Phillipps replaced the regexp stuff with Henry Spencer's version, and
- Xdid some other speed-ups and tinkerings. See below.
- XLewis Carroll wrote Alice's Adventures in Wonderland;
- XJames Joyce wrote Finnegans Wake; they are clearly the spiritual wellsprings.
- X[I think Dennis Ritchie deserves a mention here, too. IGP]
- X
- X[The ed.c source contains an untoggled switch for displaying line
- Xnumbers and another for stripping high bits off characters. If you
- Xtype "se" at the ":" prompt, you will get a decimal version number.
- X-Ed L]
- X
- XChanges by IGP since the last comp.binaries.ibm.pc posting:
- X
- XRegular expression code replaced with Henry Spencer's (lightly hacked).
- XUnneccessary text copying eliminated, and the remaining quadratic-time
- Xalgorithms to track line numbers removed. The program now remembers a pointer
- Xto the current line.
- XAll this has speeded up "g" by a factor of 20-50, so now I've documented it :-).
- XLogic fixed in egets to eliminate redundant tests.
- XA bug in <multiline> s/.../\n/ has been fixed.
- XAll out-of-memory errors should now be reported (many were ignored before).
- XA Turbo-C dependency ("cdecl") has been #ifdefed.
- XAll routines now have prototypes.
- XIan Phillipps (probably contactable via ex-igp@camcon.co.uk,
- Xbut don't bank on it)
- END_OF_FILE
- if test 6675 -ne `wc -c <'ed.man'`; then
- echo shar: \"'ed.man'\" unpacked with wrong size!
- fi
- # end of 'ed.man'
- fi
- if test -f 'read.me' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'read.me'\"
- else
- echo shar: Extracting \"'read.me'\" \(3023 characters\)
- sed "s/^X//" >'read.me' <<'END_OF_FILE'
- XHere is a version of the unix "ed" editor.
- XFor its history, please see the manual page.
- X
- XThis source uses a very slightly hacked version of Henry Spencer's
- XRegexp package. The only difference from Henry's original is that regsub
- Xnow returns a value, so it should be compatible with other uses of this
- Xpackage.
- X
- XI'm sure that Henry's package is in an archive server somewhere, but I
- Xjust mailed him (for his address, look in /usr/spool/news/.... :-)
- Xand was sent them by return. Don't you all do the same, though!
- X
- XHere are the diffs from Henry's original:
- X
- X*** regexp.h.orig Fri Sep 29 11:23:29 1989
- X--- regexp.h Wed Nov 22 12:31:41 1989
- X***************
- X*** 15,21 ****
- X char program[1]; /* Unwarranted chumminess with compiler. */
- X } regexp;
- X
- X extern regexp *regcomp();
- X extern int regexec();
- X! extern void regsub();
- X extern void regerror();
- X--- 15,29 ----
- X char program[1]; /* Unwarranted chumminess with compiler. */
- X } regexp;
- X
- X+ #ifdef __STDC__
- X+ extern regexp *regcomp( char * );
- X+ extern int regexec( regexp*, char* );
- X+ extern char *regsub( regexp*, char*, char* );
- X+ extern void regerror( char* );
- X+ #else
- X extern regexp *regcomp();
- X extern int regexec();
- X! extern char *regsub();
- X extern void regerror();
- X+ #endif
- X*** regsub.c.orig Fri Sep 29 11:23:33 1989
- X--- regsub.c Wed Nov 22 12:18:52 1989
- X***************
- X*** 18,23 ****
- X--- 18,27 ----
- X *
- X * 3. Altered versions must be plainly marked as such, and must not
- X * be misrepresented as being the original software.
- X+ *
- X+ * This version modified by Ian Phillipps to return pointer to terminating
- X+ * NUL on substitution string. [ Temp mail address ex-igp@camcon.co.uk ]
- X+ *
- X */
- X #include <stdio.h>
- X #include <regexp.h>
- X***************
- X*** 32,38 ****
- X /*
- X - regsub - perform substitutions after a regexp match
- X */
- X! void
- X regsub(prog, source, dest)
- X regexp *prog;
- X char *source;
- X--- 36,43 ----
- X /*
- X - regsub - perform substitutions after a regexp match
- X */
- X! char *
- X regsub(prog, source, dest)
- X regexp *prog;
- X char *source;
- X***************
- X*** 47,57 ****
- X
- X if (prog == NULL || source == NULL || dest == NULL) {
- X regerror("NULL parm to regsub");
- X! return;
- X }
- X if (UCHARAT(prog->program) != MAGIC) {
- X regerror("damaged regexp fed to regsub");
- X! return;
- X }
- X
- X src = source;
- X--- 52,62 ----
- X
- X if (prog == NULL || source == NULL || dest == NULL) {
- X regerror("NULL parm to regsub");
- X! return NULL;
- X }
- X if (UCHARAT(prog->program) != MAGIC) {
- X regerror("damaged regexp fed to regsub");
- X! return NULL;
- X }
- X
- X src = source;
- X***************
- X*** 74,82 ****
- X dst += len;
- X if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
- X regerror("damaged match string");
- X! return;
- X }
- X }
- X }
- X! *dst++ = '\0';
- X }
- X--- 79,89 ----
- X dst += len;
- X if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
- X regerror("damaged match string");
- X! return NULL;
- X }
- X }
- X }
- X! *dst = '\0';
- X! return dst;
- X }
- X*************** end of diffs *****************
- END_OF_FILE
- if test 3023 -ne `wc -c <'read.me'`; then
- echo shar: \"'read.me'\" unpacked with wrong size!
- fi
- # end of 'read.me'
- fi
- echo shar: End of shell archive.
- exit 0
-